/* IMPLEMENATION OF K-MEANS FOR PURE DATA: UNSUPERVISIONED MACHINE LEARNING ALGORITHM
 * FOR DATA CLUSTERIZATION.
 *  
 *  by Adriano Monteiro, december, 27, 2012. contact: monteiro.adc@gmaill.com
 *  
 */

#include "m_pd.h"
#include <stdlib.h>
#include <math.h>


static t_class *halfregu_class;

typedef struct _halfregu {
        t_object x_obj;
        
  
        // leitura da array source
        t_word *src_vec;
        t_symbol *src_arrayname;
    	int src_array_points;
    	
        // leitura da array destine
        t_word *dst_vec;
        t_symbol *dst_arrayname;
       	int dst_array_points;
                
                  
        
}t_halfregu;

/*********************** INTERNAL FUNCTIONS  *******************************/

static void halfregu(double *y, t_floatarg size){
	
	int i, L_dn = 0, L_up = 0, L_dn_1, L_up_1, edge_dn, up_i = 0, accum;
	int *dy, *edge_up; 
	
	dy = (int *)getbytes((size-1)* sizeof(int));
	
	for(i=0; i<size; i++) 
		y[i] = (y[i] > 0);
	for(i=1; i<size-1; i++){
		dy[i] = (int)(y[i]-y[i-1]);
		if(dy[i] == 1){
			L_up++;
			//if(L_up == 1)
				//L_up_1 = i;
		}else 
			if(dy[i] == -1){
				L_dn++;
				dy[i] = 0;
				//if(L_dn == 1)
					//L_dn_1 = i;
			}
	}
	
	
	if(L_dn * L_up){
		if(y[0] == 0){
			edge_up = (int *)getbytes((L_up+1)* sizeof(int));
			edge_up[L_up] = size;
			
			for(i=0; i < size-1; i++){
				if(dy[i] == 1){
					edge_up[up_i] = i;
					up_i++;
				}
			}
			for(i=0; i < L_dn; i++){
				edge_dn = round((edge_up[i] + edge_up[i+1])/2.0);
				dy[edge_dn] = dy[edge_dn] -1;
			}
			y[0]=0;
			accum =0;
			for(i=1; i < size; i++){
				accum = accum + dy[i];
				y[i]= accum;
			}
			freebytes(edge_up,(L_up+1)* sizeof(int));		
			
		}else {
			edge_up = (int *)getbytes((L_up+2)* sizeof(int));
			edge_up[0] = 0;
			edge_up[L_up+1] = size;
			
			for(i=0; i < size-1; i++){
				if(dy[i] == 1){
					edge_up[up_i] = i;
					up_i++;
				}
			}
			for(i=0; i < L_dn; i++){
				edge_dn = round((edge_up[i] + edge_up[i+1])/2.0);
				dy[edge_dn] = dy[edge_dn] -1;
			}
			y[0]=1;
			accum = 1;
			for(i=1; i < size; i++){
				accum = accum + dy[i];
				y[i]= accum;
			}
			freebytes(edge_up,(L_up+2)* sizeof(int));
		}
	}
	freebytes(dy, (size-1)* sizeof(int));
}

/******************* BANG MESSAGE ***************************************/

void halfregu_bang(t_halfregu *x) {
	
	int i;
	double *wav;
	t_garray *a, *b;

	// access array
	if(!(a = (t_garray *)pd_findbyclass(x->src_arrayname, garray_class)))
	  	pd_error(x, "%s: no such array", x->src_arrayname->s_name);
	else if(!garray_getfloatwords(a, &x->src_array_points, &x->src_vec))
		pd_error(x, "%s: bad template for wav2aud", x->src_arrayname->s_name);	
	
	if(!(b = (t_garray *)pd_findbyclass(x->dst_arrayname, garray_class)))
		pd_error(x, "%s: no such array", x->dst_arrayname->s_name);
	else if(!garray_getfloatwords(b, &x->dst_array_points, &x->dst_vec))
		pd_error(x, "%s: bad template for wav2aud", x->dst_arrayname->s_name);	
	
	wav = (double *)getbytes(x->src_array_points * sizeof(double));		// buffer for array data (original signal)
						 
	for(i=0; i < x->src_array_points; i++)wav[i] = x->src_vec[i].w_float;  // copy array
		
	halfregu(wav, x->src_array_points);
	
	for(i=0; i < x->src_array_points; i++)x->dst_vec[i].w_float = wav[i];
		
	garray_redraw(b);
			
	// free local memory
	freebytes(wav, x->src_array_points * sizeof(double));
		
	
    
}

/****************************** DATA ACESS METHOD **********************************/


		
/************************** OBJECT CREATION AND SETUP *************************************/


void *halfregu_new(t_symbol *s, int argc, t_atom *argv){
     t_halfregu *x = (t_halfregu *)pd_new(halfregu_class);
     
  // acesso a array copiado do tabletool do brent 	
	t_garray *a, *b;
 		
  	if(atom_getsymbol(argv)){
  		x->src_arrayname = atom_getsymbol(argv);

  		if(!(a = (t_garray *)pd_findbyclass(x->src_arrayname, garray_class)))
  		        pd_error(x, "%s: no such array", x->src_arrayname->s_name);
  		 else if(!garray_getfloatwords(a, &x->src_array_points, &x->src_vec))
  		    	pd_error(x, "%s: bad template for wav2aud", x->src_arrayname->s_name);	
  		}
  		else
  			post("WARNING: no array specified.");
  		
  	if(atom_getsymbol(argv+1)){
  		 x->dst_arrayname = atom_getsymbol(argv+1);

  		 if(!(b = (t_garray *)pd_findbyclass(x->dst_arrayname, garray_class)))
  		        pd_error(x, "%s: no such array", x->dst_arrayname->s_name);
  		 else if(!garray_getfloatwords(b, &x->dst_array_points, &x->dst_vec))
  		     	pd_error(x, "%s: bad template for wav2aud", x->dst_arrayname->s_name);	
  		 }
  		 else
  		 		post("WARNING: no array specified.");
  		
    
     return (void *) x;
}

    
void halfregu_setup(void) {
     halfregu_class = class_new(gensym("halfregu"), (t_newmethod)halfregu_new, 
     0, sizeof(t_halfregu), CLASS_DEFAULT, A_GIMME, 0);
      

    class_addbang(halfregu_class, halfregu_bang);
 
}

